package com.jy.api.payUtil;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.NameValuePair;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.message.BasicNameValuePair;

import java.io.File;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class HttpRequestModel {
	private HttpEntity 						httpEntity;//http请求数据
	private HttpRequestBase					httpRequestBase;//post请求
	private HttpHost 						proxy;//代理服务器
	private CredentialsProvider 			credsProvider ;//代理服务器认证
	private boolean 						isHttps;//是否是https
	private boolean 						isTwoAuth;//是否是双向认证
	private TwoWayAuthModel 				twoWayAuthModel;//双向认证的实体
	private String 							logdata;//日志
	private ProtocolType[] 					protocols;//通讯协议  除非指定，否则都支持所有的通讯协议
	private String 							httpName;//接口名称
	private int								connectTimeout=100000;//默认连接超时时间为10秒
	private int								connectionRequestTimeout=50000;//设置默认请求超时时间为5秒
	private int								socketTimeout=60000;//设置默认socket通讯超时时间
	public HttpRequestModel(){}
	public HttpRequestModel(String name){
		this.httpName=name;
	}

	public String getHttpName() {
		return httpName;
	}
	public HttpEntity getHttpEntity() {
		return httpEntity;
	}

	public HttpHost getProxy() {
		return proxy;
	}

	public HttpRequestBase getHttpRequestBase() {
		return httpRequestBase;
	}
	public CredentialsProvider getCredsProvider() {
		return credsProvider;
	}

	public boolean isHttps() {
		return isHttps;
	}

	public boolean isTwoAuth() {
		return isTwoAuth;
	}
	public TwoWayAuthModel getTwoWayAuthModel() {
		return twoWayAuthModel;
	}
	public String getLogdata() {
		return logdata;
	}
	public ProtocolType[] getProtocols() {
		return protocols;
	}

	public void setProtocols(ProtocolType[] protocols) {
		this.protocols = protocols;
	}

	public int getConnectTimeout() {
		return connectTimeout;
	}
	public void setConnectTimeout(int connectTimeout) {
		this.connectTimeout = connectTimeout;
	}
	public int getConnectionRequestTimeout() {
		return connectionRequestTimeout;
	}
	public void setConnectionRequestTimeout(int connectionRequestTimeout) {
		this.connectionRequestTimeout = connectionRequestTimeout;
	}
	public int getSocketTimeout() {
		return socketTimeout;
	}
	public void setSocketTimeout(int socketTimeout) {
		this.socketTimeout = socketTimeout;
	}

	public void addHeader(String name,String value){
		httpRequestBase.addHeader(name,value);
	}
	/**
	 * 构建默认请求对象
	 * @param uri
	 * @param requestData
	 * @param contextType
	 * @return
	 */
	public static HttpRequestModel getInstance(String uri,String requestData,HttpRequestContextType contextType){
		HttpRequestModel httpRequestModel = new HttpRequestModel();
		httpRequestModel.buidHttpPost(uri, requestData, contextType);
		if(httpRequestModel.isHttps()){
			httpRequestModel.setProtocols(ProtocolType.values());
		}
		return httpRequestModel;
	}
	public static HttpRequestModel getInstanceGBK(String uri,String requestData,HttpRequestContextType contextType){
		HttpRequestModel httpRequestModel = new HttpRequestModel();
		httpRequestModel.buidHttpPostGBK(uri, requestData, contextType);
		if(httpRequestModel.isHttps()){
			httpRequestModel.setProtocols(ProtocolType.values());
		}
		return httpRequestModel;
	}
	/**
	 * 构建默认请求对象
	 * @param uri
	 * @param requestData
	 * @param contextType
	 * @return
	 */
	public static HttpRequestModel getInstance(String uri,Map<String, Object> requestData,HttpRequestContextType contextType){
		HttpRequestModel httpRequestModel = new HttpRequestModel();
		httpRequestModel.buidHttpPost(uri, requestData, contextType);
		if(httpRequestModel.isHttps()){
			httpRequestModel.setProtocols(ProtocolType.values());
		}
		return httpRequestModel;
	}
	/**
	 * 构建默认请求对象
	 * @param uri
	 * @param javaObject
	 * @param contextType
	 * @return
	 */
	public static HttpRequestModel getInstance(String uri,Object javaObject,HttpRequestContextType contextType){
		HttpRequestModel httpRequestModel = new HttpRequestModel();
		httpRequestModel.buidHttpPost(uri, javaObject, contextType);
		if(httpRequestModel.isHttps()){
			httpRequestModel.setProtocols(ProtocolType.values());
		}
		return httpRequestModel;
	}
	/**
	 * 构建Post请求，并且为准备post数据
	 * @param uri post请求地址
	 * @param requestData post请求数据
	 * @param contextType 请求数据类型
	 * @return
	 */
	public HttpRequestModel buidHttpPost(String uri,String requestData,HttpRequestContextType contextType){
		HttpPost httpPost = new HttpPost(uri);
		if(StringUtils.isNotEmpty(requestData)){
			logdata = requestData;
			buildHttpEntity(requestData, contextType);
			httpPost.setEntity(httpEntity);
		}
		this.httpRequestBase = httpPost;
		isHttps = uri.toLowerCase().startsWith("https");
		return this;
	}
	public HttpRequestModel buidHttpPostGBK(String uri,String requestData,HttpRequestContextType contextType){
		HttpPost httpPost = new HttpPost(uri);
		if(requestData!=null){
			logdata = requestData;
			buildHttpEntityGBK(requestData, contextType);
			httpPost.setEntity(httpEntity);
		}
		isHttps = uri.toLowerCase().startsWith("https");
		return this;
	}
	/**
	 * 构建Post请求，并且为准备post数据
	 * @param uri post请求地址
	 * @param requestData post请求Map键值对对象
	 * @param contextType 请求数据类型
	 * @return
	 */
	public HttpRequestModel buidHttpPost(String uri,Map<String, Object> requestData,HttpRequestContextType contextType){
		HttpPost httpPost = new HttpPost(uri);
		if(requestData!=null){
			logdata = JSON.toJSONString(requestData);
			buildHttpEntity(requestData, contextType);
			httpPost.setEntity(httpEntity);
		}
		this.httpRequestBase = httpPost;
		isHttps = uri.toLowerCase().startsWith("https");
		return this;
	}
	/**
	 * 构建Post请求，并且为准备post数据
	 * @param uri post请求地址
	 * @param javaObject post请求java对象
	 * @param contextType 请求数据类型
	 * @return
	 */
	public HttpRequestModel buidHttpPost(String uri,Object javaObject,HttpRequestContextType contextType){
		HttpPost httpPost = new HttpPost(uri);
		if(javaObject!=null){
			buildHttpEntity(javaObject, contextType);
			logdata = JSON.toJSONString(javaObject);
			httpPost.setEntity(httpEntity);
		}
		this.httpRequestBase = httpPost;
		isHttps = uri.toLowerCase().startsWith("https");
		return this;
	}
	public HttpRequestModel buidHttpPostGBK(String uri,Object javaObject,HttpRequestContextType contextType){
		HttpPost httpPost = new HttpPost(uri);
		if(javaObject!=null){
			buildHttpEntityGBK(javaObject, contextType);
			logdata = JSON.toJSONString(javaObject);
			httpPost.setEntity(httpEntity);
		}
		this.httpRequestBase = httpPost;
		isHttps = uri.toLowerCase().startsWith("https");
		return this;
	}
	public HttpRequestModel buidHttpGet(String uri){
		this.httpRequestBase = new HttpGet(uri);
		isHttps = uri.toLowerCase().startsWith("https");
		return this;
	}
	/**
	 * 设置代理服务器
	 * @param hostname 代理服务地址
	 * @param port 代理端口
	 * @param httpType 代理服务请求类型
	 * @return
	 */
	public HttpRequestModel buildProxy(String hostname,int port,
			HttpType httpType,String username,String password){
		String protocol = httpType.name().toLowerCase();
		proxy = new HttpHost(hostname, port, protocol);
		credsProvider = new BasicCredentialsProvider();
		credsProvider.setCredentials(new AuthScope(proxy), new UsernamePasswordCredentials(username, password));
		return this;
	}
	/**
	 * 设置请求数据
	 * @param data
	 * @param contextType
	 * @return
	 */
	private HttpRequestModel buildHttpEntity(String data,HttpRequestContextType contextType){
		JlpayAssert.notNull(contextType, "must be input contextType");
		if(contextType.equals(HttpRequestContextType.JSON)){
			httpEntity = new StringEntity(data, ContentType.APPLICATION_JSON);
		}else if(HttpRequestContextType.TEXT.equals(contextType)){
			httpEntity = new StringEntity(data, ContentType.create("text/plain", Charset.forName("UTF-8")));
		}else if(contextType.equals(HttpRequestContextType.XML)){
			httpEntity = new StringEntity(data, ContentType.create("application/xml", Charset.forName("UTF-8")));
		}else if(contextType.equals(HttpRequestContextType.BYTE_ARRAY)){
			httpEntity = new ByteArrayEntity(data.getBytes());
		}
		return this;
	}
	public HttpRequestModel buidHttpPost(String uri,byte[] data){
		HttpPost httpPost = new HttpPost(uri);
		httpEntity = new ByteArrayEntity(data);
		httpPost.setEntity(httpEntity);
		this.httpRequestBase = httpPost;
		isHttps = uri.toLowerCase().startsWith("https");
		return this;
	}
	private HttpRequestModel buildHttpEntityGBK(String data,HttpRequestContextType contextType){
		JlpayAssert.notNull(contextType, "must be input contextType");
		if(contextType.equals(HttpRequestContextType.JSON)){
			httpEntity = new StringEntity(data, ContentType.create("application/json", Charset.forName("GBK")));
		}else if(HttpRequestContextType.TEXT.equals(contextType)){
			httpEntity = new StringEntity(data, ContentType.create("text/plain", Charset.forName("GBK")));
		}else if(contextType.equals(HttpRequestContextType.XML)){
			httpEntity = new StringEntity(data, ContentType.create("application/xml", Charset.forName("GBK")));
		}else if(contextType.equals(HttpRequestContextType.BYTE_ARRAY)){
			httpEntity = new ByteArrayEntity(data.getBytes());
		}
		return this;
	}

	/**
	 * 设置数据请求
	 * @param requestData
	 * @param contextType
	 * @return
	 */
	private HttpRequestModel buildHttpEntity(Map<String, Object> requestData,HttpRequestContextType contextType){
		if(contextType.equals(HttpRequestContextType.JSON)){
			httpEntity = new StringEntity(JSON.toJSONString(requestData), ContentType.APPLICATION_JSON);
		}else if(contextType.equals(HttpRequestContextType.XML)){
			throw new JlpayException("86", "不支持该数据协议，如果需要xml格式发送，请使用buildHttpEntity(Object javaObject,HttpRequestContextType contextType)方法构建HttpEntity");
		}else if(contextType.equals(HttpRequestContextType.TEXT)){
			List<NameValuePair> pairList = new ArrayList<>(requestData.size());
			for (Map.Entry<String, Object> entry : requestData.entrySet()) {
				if(null != entry.getValue())
				{
					NameValuePair pair = new BasicNameValuePair(entry.getKey(), entry.getValue().toString());
					pairList.add(pair);
				}
			}
			httpEntity = new UrlEncodedFormEntity(pairList, Charset.forName("UTF-8"));
		}else if(contextType.equals(HttpRequestContextType.TEXT_WITH_FILE)){
			MultipartEntityBuilder builder = MultipartEntityBuilder.create();
			for(Map.Entry<String,Object> entry : requestData.entrySet()){
				Object obj = entry.getValue();
				if(obj instanceof File){
					File file = (File)obj;
					FileBody bin = new FileBody(file);
					builder.addPart(entry.getKey(), bin);
				}else if(obj instanceof UploadFileStream){
					UploadFileStream stream = (UploadFileStream)obj;
					builder.addBinaryBody(entry.getKey(), stream.getStream(), ContentType.create("multipart/form-data"), stream.getFileName());
				}else if(obj instanceof InputStream){
					InputStream stream = (InputStream)obj;
					String name = entry.getKey();
					String key = name.contains(".")?name.substring(0,name.indexOf(".")):name;

//					builder.addPart(key)
					builder.addBinaryBody(key, stream, ContentType.create("multipart/form-data"), name);
				}else{
					String value = obj.toString();
					StringBody comment = new StringBody(value,ContentType.APPLICATION_JSON);
					builder.addPart(entry.getKey(), comment);
				}
			}
			httpEntity = builder.build();
		}else if(contextType.equals(HttpRequestContextType.BYTE_ARRAY)){
			httpEntity = new ByteArrayEntity(JSON.toJSONString(requestData).getBytes());
		}
		return this;
	}
	//
	private HttpRequestModel buildHttpEntity(Object javaObject,HttpRequestContextType contextType){
		if(contextType.equals(HttpRequestContextType.JSON)){
			httpEntity = new StringEntity(JSON.toJSONString(javaObject), ContentType.APPLICATION_JSON);
		}else if(contextType.equals(HttpRequestContextType.XML)){
			String xmlData = XMLHelper.ojbectToXmlWithCDATA(javaObject);
			httpEntity = new StringEntity(xmlData, ContentType.TEXT_XML);
		}else if(contextType.equals(HttpRequestContextType.TEXT)){
			JSONObject json = (JSONObject) JSON.toJSON(javaObject);
			List<NameValuePair> pairList = new ArrayList<>(json.size());
			for (Map.Entry<String, Object> entry : json.entrySet()) {
				if(null != entry.getValue())
				{
					NameValuePair pair = new BasicNameValuePair(entry.getKey(), entry.getValue().toString());
					pairList.add(pair);
				}
			}
			httpEntity = new UrlEncodedFormEntity(pairList, Charset.forName("UTF-8"));
		}else if(contextType.equals(HttpRequestContextType.BYTE_ARRAY)){
			httpEntity = new ByteArrayEntity(javaObject.toString().getBytes());
		}
		return this;
	}
	private HttpRequestModel buildHttpEntityGBK(Object javaObject,HttpRequestContextType contextType){
		if(contextType.equals(HttpRequestContextType.JSON)){
			httpEntity = new StringEntity(JSON.toJSONString(javaObject),  ContentType.create("application/json", Charset.forName("GBK")));
		}else if(contextType.equals(HttpRequestContextType.XML)){
			String xmlData = XMLHelper.ojbectToXmlWithCDATA(javaObject);
			httpEntity = new StringEntity(xmlData,  ContentType.create("text/xml", Charset.forName("GBK")) );
		}else if(contextType.equals(HttpRequestContextType.TEXT)){
			JSONObject json = (JSONObject) JSON.toJSON(javaObject);
			List<NameValuePair> pairList = new ArrayList<>(json.size());
			for (Map.Entry<String, Object> entry : json.entrySet()) {
				if(null != entry.getValue())
				{
					NameValuePair pair = new BasicNameValuePair(entry.getKey(), entry.getValue().toString());
					pairList.add(pair);
				}
			}
			httpEntity = new UrlEncodedFormEntity(pairList, Charset.forName("GBK"));
		}else if(contextType.equals(HttpRequestContextType.BYTE_ARRAY)){
			httpEntity = new ByteArrayEntity(javaObject.toString().getBytes());
		}
		return this;
	}
	/**
	 * 加载双向认证证书
	 * @param twoWayAuthModel
	 * @return
	 */
	public HttpRequestModel buildCertAuth(TwoWayAuthModel twoWayAuthModel){
		isTwoAuth = true;
		this.twoWayAuthModel = twoWayAuthModel;
		return this;
	}
}
